package com.sqx.modules.health.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
import com.sqx.modules.health.entity.*;
import com.sqx.modules.health.service.*;
import com.sqx.modules.health.utils.DateUtil;
import com.sqx.modules.sys.entity.SysUserEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.*;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author gxy
 * @since 2022-06-22
 */
@Service
public class ReportsImpl implements IReportService {

    @Autowired
    private IUserService userService;

    @Autowired
    private IRecordService recordService;

    @Autowired
    private IHospitalService hospitalService;

    @Autowired
    private ISurveyrecordService surveyrecordService;

    @Value("${server.ip}")
    private String serverIp;

    final public List ruturnList= new ArrayList();

    @Value("${files.upload.reportpath}")
    private String fileReportpath;

    @Value("${files.upload.reporttemplatepath}")
    private String templatePath;

    @Override
    public boolean fillBloodTemplate(JSONObject jsonObject) {
        // 模板路径
        String tPath = templatePath +"/paintReport.pdf";

        // 生成的新文件路径E:\WorkSpaces\serve\dist\static\reports
        String paintidPDFPath =fileReportpath+"/"+jsonObject.getString("paintid")+".pdf";
        String reportPDFPath =fileReportpath+"/"+jsonObject.getString("paintid")+"report.pdf";
        String dataPDFPath =fileReportpath+"/"+jsonObject.getString("paintid")+"data.pdf";

        PdfReader reader;
        FileOutputStream out;
        ByteArrayOutputStream bos;
        PdfStamper stamper;

        ruturnList.clear();
        try {
            out = new FileOutputStream(reportPDFPath);// 输出流
            reader = new PdfReader(tPath);// 读取pdf模板
            bos = new ByteArrayOutputStream();
            stamper = new PdfStamper(reader, bos);
            AcroFields form = stamper.getAcroFields();

            List<String> list=new ArrayList<String>();

            String recordid= jsonObject.getString("recordid");
            Record oneRecord = recordService.getById((Serializable) recordid);
            SysUserEntity doctorUser = userService.getById(oneRecord.getDoctorid());
            Hospital hospital = hospitalService.getById(doctorUser.getHid());

            // 入口方法：
            //1、获取患者基本信息
//            User user = userService.getById(jsonObject.getString("uid"));
            SysUserEntity user = userService.getById(oneRecord.getUid());
            ruturnList.add(hospital.getName());
            ruturnList.add("姓名："+user.getNickName());
            ruturnList.add(ObjectUtil.equals(user.getGender(), 1) ? "性别：男" : "性别：女");
            ruturnList.add("年龄："+user.getAge()+"岁");
            String today = DateUtil.parseStr(new Date(),"yyyy-MM-dd");

            //检查日期
            ruturnList.add("检查日期："+oneRecord.getRecordtime());
            String paintid= jsonObject.getString("paintid");
            //2、获取血压基本数据
            QueryWrapper<Surveyrecord> SurqueryWrapper = new QueryWrapper<Surveyrecord>().eq(ObjectUtil.isNotEmpty(paintid), "patid", paintid);
            List<Surveyrecord> listAll = surveyrecordService.list(SurqueryWrapper);
            //List<Surveyrecord> listAll = (List<Surveyrecord>) surveyrecordService.((Serializable)(jsonObject.getString("paintid")));
            List<Surveyrecord> rDay = new ArrayList<Surveyrecord>();
            List<Surveyrecord> rNight = new ArrayList<Surveyrecord>();

            //时间段分布 6点之前 7点之后
            rNight = listAll.stream().filter(record ->
                    record.getSampleDate().getHour()<6|| (19<=record.getSampleDate().getHour()&&record.getSampleDate().getHour()<=24)
            ).collect(Collectors.toList());
            rDay = listAll.stream().filter(record ->
                    (6<=record.getSampleDate().getHour()&&record.getSampleDate().getHour()<19)
            ).collect(Collectors.toList());

            //3、算法方法
            calculatePat(listAll);
            calculatePat(rDay);
            calculatePat(rNight);

            ruturnList.add("");//医生诊断结果
//            ruturnList.add(""+doctorUser.getNickName());
            ruturnList.add("");
            ruturnList.add("报告日期："+today);
            //输出构建
            for (int i = 0; i < ruturnList.size(); i++) {
                list.add(ruturnList.get(i)==null?"":ruturnList.get(i).toString());
            }

            int i = 0;
            Iterator<String> it = form.getFields().keySet().iterator();
            while (it.hasNext()) {
                String name = it.next().toString();
                form.setField(name, list.get(i));
                i++;
            }
            stamper.setFormFlattening(true);// 如果为false那么生成的PDF文件还能编辑，一定要设为true
            stamper.close();
            Document doc = new Document();
            PdfCopy copy = new PdfCopy(doc, out);
            doc.open();
            getSysPre(user,dataPDFPath, doctorUser, hospital,oneRecord,listAll);
            PdfImportedPage importPage = copy.getImportedPage(new PdfReader(bos.toByteArray()), 1);
            copy.addPage(importPage);
            doc.close();
        } catch (IOException e) {
            System.out.println(1);
            return false;
        } catch (DocumentException e) {
            System.out.println(2);
            return false;
        }

        List sourceFilePaths = new ArrayList();
        sourceFilePaths.add(reportPDFPath);//报告
        sourceFilePaths.add(dataPDFPath);//数据
        mergePdfFile(sourceFilePaths,paintidPDFPath);

        File myObj = new File(reportPDFPath);myObj.delete();
        File myObj1 = new File(dataPDFPath);myObj1.delete();

        return true;
    }
    /**
     *  动态血压数据
     *
     * @param user 患者信息
     * @param doctor  医生信息
     * @param top20List
     * @return String 报表生成状态
     */
    public Document getSysPre(SysUserEntity user, String dataPDFPath, SysUserEntity doctor, Hospital hospital, Record oneRecord, List<Surveyrecord> top20List) throws DocumentException, IOException {
        System.out.println("Top20 document written start ....");
        Document document = new Document();
        try {
            PdfWriter pdfWriter = PdfWriter.getInstance(document, new FileOutputStream(dataPDFPath));
            //            String os = System.getProperties().getProperty("os.name");
//            String prefixFont = "";
////            if (os.startsWith("win") || os.startsWith("Win")) {
//            prefixFont = "C:\\Windows\\Fonts" + File.separator;
////            } else {
////                prefixFont = "/usr/share/fonts/chinese" + File.separator;
////            }
            String fontPath = templatePath +"/msyh.ttf";
//            String fontPath = "D:\\font\\msyh.ttf";
            BaseFont baseFont1 = BaseFont.createFont(fontPath, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
            Font yahei12 = new Font(baseFont1, 12f); //微软雅黑 小四
            Font yahei8 = new Font(baseFont1, 10f); //微软雅黑 小四
            Font fontTitle= new Font(baseFont1, 8f);
            document.newPage();
            document.open();
            //创建表名称
            Paragraph title= new Paragraph(hospital.getName()+"\n动态血压数据分析"+"\n\n", yahei12);
            title.setAlignment(Paragraph.ALIGN_CENTER);
            document.add(title);
            Paragraph patientInfo= new Paragraph("                  姓名："+user.getNickName()
                    +"            性别："+(ObjectUtil.equals(user.getGender(), 1) ? "男" : "女")+""
                    +"          年龄："+user.getAge()+"岁\n\n", yahei8);
            patientInfo.setAlignment(Paragraph.ALIGN_LEFT);
            document.add(patientInfo);
            String printTime = DateUtil.parseStr(new Date(),DateUtil.FMT_YYYYMMDD_HHMMSS);
            Paragraph timeNote=new Paragraph("检查日期："+oneRecord.getRecordtime()+"                             \n\n",yahei8);
            timeNote.setAlignment(Paragraph.ALIGN_RIGHT);
            document.add(timeNote);

            //创建PdfTable对象
            PdfPTable table=new PdfPTable(5);
            //设置各列的列宽
            table.setTotalWidth(new float[]{70,130,100,100,100});
            //添加表格内容
            table.addCell(getHeaderCell("序号",fontTitle));
            table.addCell(getHeaderCell("测量时间",fontTitle));
            table.addCell(getHeaderCell("收缩压（mmHg）",fontTitle));
            table.addCell(getHeaderCell("舒张压（mmHg）",fontTitle));
            table.addCell(getHeaderCell("心率（次）",fontTitle));
            //当前月当前年
            //endTime<=nowDate 直接传入查
            if(top20List!=null) {

                for (int i = 0; i < top20List.size(); i++) {
                    table.addCell(getPDFCell((i+1)+"", fontTitle));
                    table.addCell(getPDFCell(top20List.get(i).getSampleDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))==null?"":top20List.get(i).getSampleDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")), fontTitle));
                    table.addCell(getPDFCell(top20List.get(i).getShrink().toString(), fontTitle));
                    table.addCell(getPDFCell(top20List.get(i).getDiastole().toString(), fontTitle));
                    table.addCell(getPDFCell(top20List.get(i).getPulse().toString(), fontTitle));

                }
            }

            Paragraph bottom= new Paragraph("                 ———————————————————————————————————————"+"\n"
                    +"                        共计："+top20List.size()+"行数据                                              "+"\n"
                    +"                 ———————————————————————————————————————"+"\n", yahei8);
            title.setAlignment(Paragraph.ALIGN_CENTER);

            System.out.println("Top20PDF document written success.");
            document.add(table);
            addBlankLine(document);
            document.add(bottom);
            document.close();
            pdfWriter.close();
        } catch (DocumentException e){
            e.printStackTrace();
        } catch (Exception e){
            e.printStackTrace();
        }
        return document;
    }
    //获取指定内容与字体的单元格
    public static PdfPCell getPDFCell(String string, Font font)
    {
        //创建单元格对象，将内容与字体放入段落中作为单元格内容
        PdfPCell cell=new PdfPCell(new Paragraph(string,font));
        cell.setHorizontalAlignment(Element.ALIGN_CENTER);
        cell.setVerticalAlignment(Element.ALIGN_MIDDLE);

        //设置最小单元格高度
        cell.setMinimumHeight(25);
        return cell;
    }

    /**
     * 合并PDF文件
     * @param sourceFilePaths 需要合并的PDF文件路径列表
     * @param destFilePath 合并后的新文件
     */
    public   void mergePdfFile(List<String> sourceFilePaths, String destFilePath) {
        if (sourceFilePaths == null || sourceFilePaths.isEmpty() || destFilePath == null) {
            return;
        }

        Document document = null;
        PdfCopy copy = null;
        OutputStream os = null;
        try {

            // 创建合并后的新文件的目录
            //Path dirPath = Paths.get(destFilePath.substring(0, destFilePath.lastIndexOf(File.separator)));
            //Files.createDirectories(dirPath);

            os = new BufferedOutputStream(new FileOutputStream(new File(destFilePath)));
            document = new Document(new PdfReader(sourceFilePaths.get(0)).getPageSize(1));
            copy = new PdfCopy(document, os);
            document.open();
            for (String sourceFilePath : sourceFilePaths) {
                // 如果PDF文件不存在，则跳过
                if (!new File(sourceFilePath).exists()) {
                    continue;
                }

                // 读取需要合并的PDF文件
                PdfReader reader = new PdfReader(sourceFilePath);
                // 获取PDF文件总页数
                int n = reader.getNumberOfPages();
                for (int j = 1; j <= n; j++) {
                    document.newPage();
                    PdfImportedPage page = copy.getImportedPage(reader, j);
                    copy.addPage(page);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (copy != null) {
                try {
                    copy.close();
                } catch (Exception ex) {
                    /* ignore */
                }
            }
            if (document != null) {
                try {
                    document.close();
                } catch (Exception ex) {
                    /* ignore */
                }
            }
            if (os != null) {
                try {
                    os.close();
                } catch (Exception ex) {
                    /* ignore */
                }
            }
        }
    }



    //获取指定内容与字体的单元格
    public static PdfPCell getHeaderCell(String string, Font font)
    {
        //创建单元格对象，将内容与字体放入段落中作为单元格内容
        PdfPCell cell=new PdfPCell(new Paragraph(string,font));
        cell.setHorizontalAlignment(Element.ALIGN_CENTER);
        cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
        cell.setBackgroundColor(BaseColor.WHITE);  /*设置表格背景颜色*/

        //设置最小单元格高度
        cell.setMinimumHeight(25);
        return cell;
    }
    //获取指定内容与字体的单元格
    public Document addBlankLine(Document document)
    {
        //创建单元格对象，将内容与字体放入段落中作为单元格内容
        Paragraph title=new Paragraph("\n");
        title.setAlignment(Paragraph.ALIGN_CENTER);
        try {
            document.add(title);
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        return document;
    }

    /**
     * 统计信息
     *
     * @param list
     */
    public List calculatePat(List<Surveyrecord> list) {
        if(list.size()==0){
            for (int i = 0; i <= 13; i++) {
                ruturnList.add("");
            }
            return ruturnList;
        }

        //收缩压，舒张压，心率 平均数
        Double sysAvg = 0D;
        Double diaAvg = 0D;
        Double pulAvg = 0D;

        // 收缩压，舒张压，报警数统计
        Integer sysWaring = 0;
        Integer diaWaring = 0;

        final Double[] sumAvg = {0D,0D,0D,0D,0D};
        list.forEach(record->{
            sumAvg[0] = sumAvg[0] +Integer.valueOf(record.getShrink()==null?0:record.getShrink());
            sumAvg[1] = sumAvg[1] +Integer.valueOf(record.getDiastole()==null?0:record.getDiastole());
            sumAvg[2] = sumAvg[2] +Integer.valueOf(record.getPulse()==null?0:record.getPulse());
            if(Integer.valueOf(record.getShrink()==null?0:record.getShrink())>=135){;
                sumAvg[3]=sumAvg[3]+1;
            }
            if(Integer.valueOf(record.getDiastole()==null?0:record.getDiastole())>=85){;
                sumAvg[4]=sumAvg[4]+1;
            }
        });

        sysAvg = sumAvg[0]/(list.size());
        diaAvg = sumAvg[1]/(list.size());
        pulAvg = sumAvg[2]/(list.size());
        sysWaring =  Double.valueOf(sumAvg[3]).intValue();
        diaWaring = Double.valueOf(sumAvg[4]).intValue();

        // 收缩压，舒张压，心率 标准差
        String standSysAvg = "";
        String standDiaAvg = "";
        String standPulAvg = "";
        Double[] sumStand = {0D,0D,0D};
        for (Surveyrecord record : list) {
            sumStand[0] = Math.pow((Double.valueOf(record.getShrink()==null?0:record.getShrink()) - sysAvg), 2);
            sumStand[1] = Math.pow((Double.valueOf(record.getDiastole()==null?0:record.getDiastole()) - diaAvg), 2);
            sumStand[2] = Math.pow((Double.valueOf(record.getPulse()==null?0:record.getPulse()) - pulAvg), 2);
        }

        standSysAvg = format4(Math.sqrt(sumStand[0]/list.size()));
        standDiaAvg = format4(Math.sqrt(sumStand[1]/list.size()));
        standPulAvg = format4(Math.sqrt(sumStand[2]/list.size()));

        //收缩压 最大 最小
        List<Surveyrecord> newSysList = list.stream().filter(record -> record.getShrink()!=null).collect(Collectors.toList());
        //最小值
        Integer minSys = newSysList.stream().mapToInt(Surveyrecord::getShrink).min().getAsInt();
        //最大值
        Integer maxSys = newSysList.stream().mapToInt(Surveyrecord::getShrink).max().getAsInt();
        //平均值
        Double averageSys = newSysList.stream().mapToInt(Surveyrecord::getShrink).average().getAsDouble();
        ruturnList.add(maxSys);
        ruturnList.add(minSys);
        ruturnList.add(format4(averageSys));
        ruturnList.add(standSysAvg);


        //舒张压 最大 最小
        List<Surveyrecord> newDiaList = list.stream().filter(record -> record.getDiastole()!=null).collect(Collectors.toList());
        //最小值
        Integer minDia = newDiaList.stream().mapToInt(Surveyrecord::getDiastole).min().getAsInt();
        //最大值
        Integer maxDia = newDiaList.stream().mapToInt(Surveyrecord::getDiastole).max().getAsInt();
        //平均值
        Double averageDia = newDiaList.stream().mapToInt(Surveyrecord::getDiastole).average().getAsDouble();
        ruturnList.add(maxDia);
        ruturnList.add(minDia);
        ruturnList.add(format4(averageDia));
        ruturnList.add(standDiaAvg);

        //心率 最大 最小
        List<Surveyrecord> newPulList = list.stream().filter(record -> record.getPulse()!=null).collect(Collectors.toList());
        //最小值
        Integer minPul = newPulList.stream().mapToInt(Surveyrecord::getPulse).min().getAsInt();
        //最大值
        Integer maxPul = newPulList.stream().mapToInt(Surveyrecord::getPulse).max().getAsInt();
        //平均值
        Double averagePul = newPulList.stream().mapToInt(Surveyrecord::getPulse).average().getAsDouble();
        ruturnList.add(maxPul);
        ruturnList.add(minPul);
        ruturnList.add(format4(averagePul));
        ruturnList.add(standPulAvg);

        ruturnList.add(sysWaring);
        ruturnList.add(diaWaring);
        return ruturnList;
    }

    /**
     * %.2f % 表示 小数点前任意位数 2 表示两位小数 格式后的结果为 f 表示浮点型
     */
    public static String format4(double value) {
        return new Formatter().format("%.2f", value).toString();
    }

}
